package memorphic.simpleloginsample.controllers
{
	import flash.events.EventDispatcher;
	import flash.events.TimerEvent;
	import flash.net.SharedObject;
	import flash.utils.Timer;
	
	import memorphic.simpleloginsample.events.LoginEvent;
	
	[Event(name="logIn", type="memorphic.simpleloginsample.events.LoginEvent")]
	[Event(name="logOut", type="memorphic.simpleloginsample.events.LoginEvent")]
	[Event(name="logInError", type="memorphic.simpleloginsample.events.LoginEvent")]
	[Event(name="register", type="memorphic.simpleloginsample.events.LoginEvent")]
	[Event(name="registerError", type="memorphic.simpleloginsample.events.LoginEvent")]
	
	/**
	 * This is a dummy class that pretends to go to a server to authenticate and register users
	 * but actually just kills a bit of time and dispatches an event.
	 * 
	 * 
	 * ROLE: Business Delegate
	 * 	The responsibilities of a Business Delegate are to:
	 * 		- Process business rules, without knowledge of the overall application or application state
	 * 		- deal with external services which may perform this role
	 * 
	 */
	public class LoginDelegate extends EventDispatcher
	{
		
		// TODO: move to resource bundle
		private static const LOGIN_FAILED:String = "Login failed. Please check that your name and password are correct, or register if you do not have an account already.";
		private static const PASSWORD_MISMATCH:String = "Registration failed. The passwords must match.";
		private static const USER_EXISTS:String = "A user with that name already exists. Please choose another name.";
		private static const FIELD_BLANK:String = "Please complete all fields.";

		
		private var lastRequestName:String;
		private var lastRequestPass:String;
		private var lastRequestAction:Function;
		
		private const requestDelayTimer:Timer = new Timer(1500, 1);
		
		
		public function LoginDelegate()
		{
			requestDelayTimer.addEventListener(TimerEvent.TIMER, onRequestDelayTimer);
		}
		
		
		/**
		 * Sumbit login creditials. For demonstration purposes, this method will emulate a delay
		 * before verifying the user name and password
		 */
		public function submitLogin(name:String, pass:String):void
		{
			lastRequestName = name;
			lastRequestPass = pass;
			emulateDelayedResponse(doLogin);
		}
		
		/**
		 * Register a new user name and password. For demonstration purposes, this method will emulate a delay
		 * before verifying the user name and password
		 */
		public function submitRegistration(name:String, pass:String, pass2:String):void
		{
			if(!name || !pass ||!pass2){
				dispatchEvent(new LoginEvent(LoginEvent.REGISTER_ERROR, name, FIELD_BLANK));		
				return;	
			}
			if(pass != pass2){
				dispatchEvent(new LoginEvent(LoginEvent.REGISTER_ERROR, name, PASSWORD_MISMATCH));
				return;				
			}
			lastRequestName = name;
			lastRequestPass = pass;
			emulateDelayedResponse(doRegistration);
		}


		public function logOut():void
		{
			dispatchEvent(new LoginEvent(LoginEvent.LOG_OUT, null));
		}

		
		
		private function emulateDelayedResponse(action:Function):void
		{
			lastRequestAction = action;
			requestDelayTimer.delay = 300 + Math.random() * 1700;
			requestDelayTimer.reset();
			requestDelayTimer.start();
		}
		
		
		private function onRequestDelayTimer(e:TimerEvent):void
		{
			requestDelayTimer.stop();
			if(lastRequestAction != null){
				lastRequestAction();
				lastRequestAction = null;
			}
		}
		
		
		private function doLogin():void
		{
			var table:Object = getAuthTable();
			if(lastRequestPass && table[lastRequestName] == lastRequestPass){
				dispatchEvent(new LoginEvent(LoginEvent.LOG_IN, lastRequestName));
			}else{
				dispatchEvent(new LoginEvent(LoginEvent.LOG_IN_ERROR, lastRequestName, LOGIN_FAILED));
			}	
		}
		
		
		private function doRegistration():void
		{
			var table:Object = getAuthTable();
			if(table.hasOwnProperty(lastRequestName)){
				dispatchEvent(new LoginEvent(LoginEvent.REGISTER_ERROR, lastRequestName, USER_EXISTS));
				return;
			}
			
			table[lastRequestName] = lastRequestPass;
			saveAuthTable();
			dispatchEvent(new LoginEvent(LoginEvent.REGISTER, lastRequestName));
		}
		
		
		
		
		private function getLocalStorage():SharedObject
		{
			return SharedObject.getLocal("memorphic.slide.samples.LoginTable", "/");
		}
		
		private function getAuthTable():Object
		{
			var localData:Object = getLocalStorage().data;
			var table:Object = localData.authTable;
			if(!table){
				table = (localData.authTable = new Object());
			}
			return table;
		}
		
		private function saveAuthTable():void
		{
			getLocalStorage().flush();
		}
		
		

	}
}

